Calcifer Calcifer 2
Linux

网站也要身份证:HTTPS 证书申请指南

2026/03/09 11:13 25 次阅读 王梓
打赏
✸ ✸ ✸

前言

你有没有想过,为什么浏览器地址栏有些网站显示小锁头🔒,有些却显示"不安全"?这背后就是 HTTPS 证书在起作用。就像人需要身份证证明身份一样,网站也需要证书来证明"我是我"。

本文将用最通俗的语言,带你搞懂 HTTPS 证书的两种申请方式:适合个人/小团队的免费自动化方案,以及适合企业的正式申请流程。

一、先搞懂几个概念

1.1 HTTPS 到底在保护什么?

想象你在咖啡馆用公共 WiFi 网上银行,如果没有 HTTPS,旁边的人可以轻松看到你的账号密码。HTTPS 就像一个加密管道,让数据在传输过程中变成乱码,只有你和服务器能看懂。

1.2 证书的三要素

🔐 私钥 Private Key 服务器独有 ⚠️ 绝对不能泄露 📜 证书 Certificate 包含公钥+身份信息 ✓ 可以公开 📝 CSR 证书签名请求 申请证书的"申请书" ✓ 可以公开

1.3 证书类型怎么选?

类型长什么样验证什么适合谁价格
DV
域名验证
显示小锁头🔒证明你拥有这个域名个人博客、小网站免费~几十元
OV
组织验证
显示小锁头🔒
点击可看公司名
证明公司真实存在企业官网几百~几千元
EV
扩展验证
显示公司名称
绿色地址栏
严格审核公司资质银行、金融、电商几千~上万元

二、免费方案:Let's Encrypt 自动化证书

2.1 为什么推荐 Let's Encrypt?

Let's Encrypt 是一个非营利组织,提供永久免费的 SSL 证书。虽然只有 DV 级别(域名验证),但对于个人网站、博客、小项目来说完全够用。

  • ✅ 完全免费,无隐藏费用
  • ✅ 自动化申请和续期
  • ✅ 支持通配符证书(*.example.com)
  • ✅ 所有主流浏览器信任

唯一的"缺点":证书有效期只有 90 天,但可以通过自动化脚本解决。

2.2 申请流程图解

🖥️ 你的服务器 🌐 Let's Encrypt ① 请求证书 ② 返回验证挑战 ③ 完成验证 HTTP: 放置验证文件 DNS: 添加TXT记录 ④ 通知验证完成 ⑤ 验证通过 签发证书 ⑥ 返回证书文件 ⑦ 安装证书 🎉 网站启用 HTTPS 自动续期,90天循环

2.3 验证方式怎么选?

HTTP-01 验证 在网站放一个验证文件 CA 访问验证 ✓ 最简单 ✗ 只能单域名 DNS-01 验证 添加一条 TXT 记录 CA 查询 DNS 验证 ✓ 支持通配符 ⚠️ 需要DNS权限 TLS-ALPN-01 特殊 TLS 握手验证 较复杂 适合特殊场景 一般不常用

2.4 首次申请:从零开始获取证书

如果你是第一次申请 Let's Encrypt 证书,需要先安装 acme.sh 客户端,然后完成首次申请。以下是完整步骤:

步骤一:安装 acme.sh

# 在线安装(推荐)
curl https://get.acme.sh | sh -s email=your-email@example.com

# 或者使用 wget
wget -O -  https://get.acme.sh | sh -s email=your-email@example.com

# 安装后重新加载 shell 环境
source ~/.bashrc

# 验证安装
acme.sh --version

步骤二:选择验证方式申请证书

方式A:HTTP-01 验证(最简单,适合单域名)

# 确保你的网站可以通过 HTTP 访问
# acme.sh 会自动在网站根目录放置验证文件

# 申请证书(自动模式)
acme.sh --issue -d example.com --webroot /var/www/html

# 如果使用 nginx,可以自动配置
acme.sh --issue -d example.com --nginx

# 申请多个单域名证书
acme.sh --issue -d example.com -d www.example.com --webroot /var/www/html

方式B:DNS-01 验证(支持通配符)

# 手动 DNS 模式(需要手动添加 TXT 记录)
acme.sh --issue -d '*.example.com' -d example.com --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please

# 执行后会输出类似内容:
# Domain: '_acme-challenge.example.com'
# TXT value: 'aBcDeFgHiJkLmNoPqRsTuVwXyZ123456'
#
# 请将此 TXT 记录添加到你的 DNS 解析

# 添加 DNS 记录后,继续验证
acme.sh --renew -d '*.example.com' -d example.com --yes-I-know-dns-manual-mode-enough-go-ahead-please

方式C:自动 DNS API(推荐,全自动)

# 如果你使用阿里云 DNS
export Ali_Key="your_access_key"
export Ali_Secret="your_access_secret"
acme.sh --issue -d '*.example.com' -d example.com --dns dns_ali

# 如果你使用腾讯云 DNS
export Tencent_SecretId="your_secret_id"
export Tencent_SecretKey="your_secret_key"
acme.sh --issue -d '*.example.com' -d example.com --dns dns_tencent

# 如果你使用 Cloudflare
export CF_Key="your_api_key"
export CF_Email="your_email@example.com"
acme.sh --issue -d '*.example.com' -d example.com --dns dns_cf

步骤三:安装证书到服务器

# 安装证书到 nginx
acme.sh --install-cert -d example.com \
  --cert-file      /etc/nginx/ssl/cert.pem  \
  --key-file       /etc/nginx/ssl/key.pem  \
  --fullchain-file /etc/nginx/ssl/fullchain.pem \
  --reloadcmd     "nginx -s reload"

# 安装通配符证书
acme.sh --install-cert -d '*.example.com' \
  --cert-file      /etc/nginx/ssl/wildcard.crt  \
  --key-file       /etc/nginx/ssl/wildcard.key  \
  --fullchain-file /etc/nginx/ssl/wildcard.fullchain.crt \
  --reloadcmd     "nginx -s reload"

步骤四:配置 Nginx 使用证书

server {
    listen 443 ssl http2;
    server_name example.com www.example.com;
    
    ssl_certificate     /etc/nginx/ssl/fullchain.pem;
    ssl_certificate_key /etc/nginx/ssl/key.pem;
    
    # SSL 优化配置
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256;
    ssl_prefer_server_ciphers off;
    ssl_session_timeout 1d;
    ssl_session_cache shared:SSL:10m;
    
    # HSTS
    add_header Strict-Transport-Security "max-age=31536000" always;
    
    location / {
        # 你的网站配置
    }
}

# HTTP 跳转 HTTPS
server {
    listen 80;
    server_name example.com www.example.com;
    return 301 https://$server_name$request_uri;
}

2.5 自动续期:让证书永不过期

Let's Encrypt 证书有效期只有 90 天,但 acme.sh 会自动设置续期任务。你也可以手动管理续期:

# 查看已安装的证书
acme.sh --list

# 手动续期某个证书
acme.sh --renew -d example.com

# 强制续期(忽略有效期检查)
acme.sh --renew -d example.com --force

# 查看自动续期任务
crontab -l | grep acme

以下是一个生产环境使用的完整续期脚本:

#!/bin/bash
# ============================================================
# Let's Encrypt 通配符证书续期脚本
# 域名: *.example.com + example.com
# ============================================================

set -e  # 遇错即停

# 配置
ACME="/root/.acme.sh/acme.sh"
CERT_DIR="/etc/nginx"
CERT_FILE="${CERT_DIR}/wildcard.crt"
KEY_FILE="${CERT_DIR}/wildcard.key"

# 是否强制续期
FORCE=""
[ "$1" = "--force" ] && FORCE="--force"

echo "========================================"
echo "  Let's Encrypt 通配符证书续期"
echo "========================================"

# 检查当前证书状态
echo "[检查] 当前证书状态:"
openssl x509 -in ${CERT_FILE} -noout -subject -dates 2>/dev/null || echo "  未找到现有证书"

# 智能判断是否需要续期(30天内过期才续)
if [ -z "$FORCE" ] && [ -f "$CERT_FILE" ]; then
    if openssl x509 -in ${CERT_FILE} -noout -checkend 2592000 >/dev/null 2>&1; then
        echo "证书有效期还有30天以上,无需续期。"
        echo "如需强制续期: bash $0 --force"
        exit 0
    fi
    echo "证书将在30天内过期,开始续期..."
fi

# 申请/续期证书
if ${ACME} --renew -d '*.example.com' -d 'example.com' \
    --yes-I-know-dns-manual-mode-enough-go-ahead-please \
    --server letsencrypt ${FORCE} 2>&1; then
    
    # 安装证书
    echo "[安装] 复制证书到nginx目录..."
    cp /root/.acme.sh/*.example.com_ecc/fullchain.cer ${CERT_FILE}
    cp /root/.acme.sh/*.example.com_ecc/*.example.com.key ${KEY_FILE}
    chmod 644 ${CERT_FILE}
    chmod 600 ${KEY_FILE}  # 私钥权限要严格
    
    # 重载nginx
    nginx -t && nginx -s reload
    
    echo "[完成] 新证书信息:"
    openssl x509 -in ${CERT_FILE} -noout -subject -dates
    echo "续期成功!"
else
    # 需要更新DNS验证
    echo "============================================"
    echo "  需要更新DNS TXT记录!"
    echo "============================================"
    echo "1. 登录DNS服务商管理后台"
    echo "2. 更新 _acme-challenge 的TXT记录值"
    echo "3. 等待1-2分钟DNS生效"
    echo "4. 验证: dig TXT _acme-challenge.example.com"
    echo "5. 重新运行: bash $0 --force"
    exit 1
fi

2.5 设置自动续期定时任务

# 编辑 crontab
crontab -e

# 添加以下内容(每月1号凌晨3点检查续期)
0 3 1 * * /root/web/script/renew_cert.sh >> /var/log/cert-renew.log 2>&1

三、企业方案:CSR 证书申请流程

3.1 什么时候需要走企业流程?

以下情况需要使用企业级证书申请流程:

  • 🏢 公司内部 PKI 系统,需要提交 CSR 给安全团队
  • 🏦 金融、医疗等行业,需要 OV/EV 级别证书
  • 📋 合规要求,证书需要正式审批流程
  • 🔐 需要证书显示公司名称(OV/EV 特性)

3.2 CSR 是什么?

CSR(Certificate Signing Request)证书签名请求,就像一份"申请书",包含:

  • 你的公钥
  • 域名信息(CN 和 SAN)
  • 组织信息(公司名、部门、城市等)

私钥你自己保留,CSR 提交给 CA,CA 验证后用它的私钥签名,返回正式证书。

3.3 企业证书申请流程图

👨‍💻 开发团队 🏛️ 证书管理员/CA ① 生成密钥对 ② 生成 CSR ③ 提交 CSR CSR文件 ④ 验证申请 ⑤ CA 签名 ⑥ 返回证书 证书文件 ⑦ 导入证书 ⑧ 配置应用 🎉 HTTPS 启用

3.4 首次申请:生成 CSR 并提交

企业级证书申请的第一步是生成 CSR(证书签名请求)。CSR 包含你的公钥和身份信息,提交给 CA 后,CA 会验证并签发证书。

步骤一:准备申请信息

在生成 CSR 之前,需要准备以下信息:

字段说明示例
C (Country)国家代码(两位)CN、US、DE
S (State)省/州Beijing、Shanghai
L (Locality)城市Beijing、Shenzhen
O (Organization)公司/组织名称Your Company Ltd
OU (Organizational Unit)部门IT Department
CN (Common Name)主域名portal.example.com
SAN (Subject Alternative Name)所有需要覆盖的域名多个域名列表

步骤二:生成密钥对和 CSR

以下是完整的 CSR 生成脚本:

#!/bin/bash
# ============================================================
# 企业级证书申请脚本 - CSR 生成
# ============================================================

# ========== 配置区域 ==========
PASSWORD="your_secure_password"      # 密钥库密码(妥善保管)
DOMAIN_NAME="example.com"             # 主域名
JKS_FILE="${DOMAIN_NAME}.jks"        # Java KeyStore
PFX_FILE="${DOMAIN_NAME}.pfx"        # PKCS#12 格式
KEY_FILE="${DOMAIN_NAME}.key"        # PEM 私钥
CSR_FILE="${DOMAIN_NAME}.csr"        # 证书签名请求
CERT_ALIAS="server_cert"              # 证书别名

# 证书主题信息(根据实际情况修改)
CN_NAME="portal.example.com"         # 主域名(Common Name)

# SAN 扩展 - 证书覆盖的所有域名
SAN_LIST="dns:portal.example.com,dns:portal.qa.example.com,dns:portal.dev.example.com,dns:api.example.com"

# ========== 步骤1:生成密钥对 ==========
echo ">>> 生成 4096 位 RSA 密钥对..."
keytool -genkey \
    -alias $CERT_ALIAS \
    -keyalg RSA \
    -keysize 4096 \
    -keystore $JKS_FILE \
    -keypass $PASSWORD \
    -storepass $PASSWORD \
    -ext san=$SAN_LIST \
    -dname "C=CN,S=Beijing,L=Beijing,O=YourCompany,OU=IT,CN=$CN_NAME"

# ========== 步骤2:转换为 PKCS#12 格式 ==========
echo ">>> 转换为 PKCS#12 格式..."
keytool -v -importkeystore \
    -srckeystore $JKS_FILE \
    -srcstoretype jks \
    -srcstorepass $PASSWORD \
    -destkeystore $PFX_FILE \
    -deststoretype pkcs12 \
    -deststorepass $PASSWORD \
    -destkeypass $PASSWORD

# ========== 步骤3:提取 PEM 私钥 ==========
echo ">>> 提取 PEM 格式私钥..."
openssl pkcs12 \
    -password pass:$PASSWORD \
    -in $PFX_FILE \
    -nocerts \
    -nodes \
    -out $KEY_FILE

# ========== 步骤4:生成 CSR ==========
echo ">>> 生成证书签名请求..."
keytool -certreq \
    -sigalg SHA256withRSA \
    -storepass $PASSWORD \
    -alias $CERT_ALIAS \
    -keystore $JKS_FILE \
    -file $CSR_FILE \
    -ext san=$SAN_LIST

# ========== 步骤5:验证 CSR ==========
echo ">>> CSR 内容验证:"
openssl req -text -noout -verify -in $CSR_FILE

# ========== 步骤6:打包 ==========
echo ">>> 打包所有文件..."
zip ${DOMAIN_NAME}.zip $JKS_FILE $PFX_FILE $KEY_FILE $CSR_FILE

echo ""
echo "========================================"
echo "  CSR 生成完成!"
echo "========================================"
echo "请将 ${CSR_FILE} 提交给证书管理员"
echo "私钥文件请妥善保管,不要泄露!"

3.5 生成的文件用途

*.jks Java KeyStore Tomcat/WebLogic Java 应用 ⚠️ 高度保密 *.pfx / *.p12 PKCS#12 Windows IIS Azure 应用 ⚠️ 高度保密 *.key PEM 私钥 Nginx / Apache Linux 服务器 ⚠️ 高度保密 *.csr 证书签名请求 提交给 CA 申请证书 ✓ 可以公开

3.6 收到证书后如何导入?

CA 签发后会返回:服务器证书、中间证书、根证书。需要按顺序导入:

# 方法1:导入到 JKS(Java 应用)
# 按顺序:根证书 → 中间证书 → 服务器证书
keytool -import -alias root -keystore server.jks -file root.crt -trustcacerts
keytool -import -alias intermediate -keystore server.jks -file intermediate.crt
keytool -import -alias server -keystore server.jks -file server.crt

# 方法2:创建 PEM 证书链(Nginx/Apache)
# 合并服务器证书和中间证书
cat server.crt intermediate.crt > fullchain.crt

# Nginx 配置
# ssl_certificate     /path/to/fullchain.crt;
# ssl_certificate_key /path/to/server.key;

3.7 证书续期:企业证书如何更新

企业级证书通常有效期 1-2 年,到期前需要续期。续期流程与首次申请类似,但有一些注意事项:

续期时机

# 检查证书剩余有效期
openssl x509 -in server.crt -noout -dates

# 计算剩余天数
echo "证书将在 $(($(date -d "$(openssl x509 -in server.crt -noout -enddate | cut -d= -f2)" +%s) - $(date +%s))) 秒后过期"

# 建议:证书过期前 30 天开始续期流程

续期方式选择

方式说明适用场景
复用私钥使用原有私钥重新生成 CSR快速续期,无需重新部署密钥
新建密钥生成新的密钥对和 CSR更安全,推荐做法
自动续期部分 CA 提供自动续期服务减少运维工作量

续期脚本示例

#!/bin/bash
# ============================================================
# 企业级证书续期脚本
# ============================================================

DOMAIN_NAME="example.com"
OLD_CERT="server.crt"
CSR_FILE="renew_${DOMAIN_NAME}.csr"

# 检查证书是否需要续期(30天内过期)
check_renewal() {
    if openssl x509 -in $OLD_CERT -noout -checkend 2592000 2>/dev/null; then
        echo "证书有效期充足,暂不需要续期"
        exit 0
    fi
    echo "证书将在30天内过期,开始续期流程..."
}

# 方式1:复用现有私钥生成 CSR(快速续期)
renew_with_existing_key() {
    # 从现有证书提取公钥信息
    openssl x509 -in $OLD_CERT -noout -text | grep -A1 "Subject Alternative Name"
    
    # 使用现有私钥生成新 CSR
    openssl req -new \
        -key server.key \
        -out $CSR_FILE \
        -subj "/C=CN/ST=Beijing/L=Beijing/O=YourCompany/OU=IT/CN=portal.example.com"
    
    echo "CSR 已生成: $CSR_FILE"
    echo "请提交给证书管理员"
}

# 方式2:生成新的密钥对(推荐)
renew_with_new_key() {
    # 生成新私钥
    openssl genrsa -out server_new.key 4096
    
    # 生成新 CSR
    openssl req -new \
        -key server_new.key \
        -out $CSR_FILE \
        -subj "/C=CN/ST=Beijing/L=Beijing/O=YourCompany/OU=IT/CN=portal.example.com" \
        -addext "subjectAltName=DNS:portal.example.com,DNS:api.example.com"
    
    echo "新密钥和 CSR 已生成"
    echo "私钥: server_new.key (请妥善保管)"
    echo "CSR: $CSR_FILE (提交给证书管理员)"
}

# 执行续期检查
check_renewal

# 选择续期方式
echo "请选择续期方式:"
echo "1) 复用现有私钥(快速)"
echo "2) 生成新密钥对(更安全,推荐)"
read -p "请输入选项 [1/2]: " choice

case $choice in
    1) renew_with_existing_key ;;
    2) renew_with_new_key ;;
    *) echo "无效选项"; exit 1 ;;
esac

续期后部署

# 收到新证书后,替换旧证书
cp server.crt server.crt.bak  # 备份旧证书
cp new_server.crt server.crt

# 如果生成了新私钥,也要更新
cp server_new.key server.key

# 验证证书和私钥是否匹配
openssl x509 -noout -modulus -in server.crt | openssl md5
openssl rsa -noout -modulus -in server.key | openssl md5
# 两个 MD5 值应该相同

# 重启服务
nginx -t && nginx -s reload
# 或
systemctl restart tomcat

四、两种方案对比总结

4.1 一图看懂差异

🆓 Let's Encrypt 💰 费用:完全免费 📅 有效期:90天(自动续期) 🔒 类型:DV 域名验证 ⚡ 自动化:高度自动化 🌐 通配符:✓ 支持 👤 适合:个人/小团队 ⏱️ 申请时间:几分钟 🏢 企业级证书 💰 费用:几百~上万元 📅 有效期:1-2年 🔒 类型:OV/EV 组织验证 ⚡ 自动化:需人工审批 🌐 通配符:需额外付费 👤 适合:企业/金融/电商 ⏱️ 申请时间:几天~几周

4.2 如何选择?

你的场景推荐方案原因
个人博客、作品集Let's Encrypt免费、自动、够用
小团队项目、测试环境Let's Encrypt快速部署、零成本
企业官网OV 证书显示公司名,更专业
金融、支付系统EV 证书最高信任级别
内网系统、企业PKICSR 模式符合企业安全规范
需要通配符证书Let's Encrypt免费支持通配符

五、实用技巧与常见问题

5.1 证书安全最佳实践

# 1. 私钥权限:只有 root 可读
chmod 600 private.key
chown root:root private.key

# 2. 证书权限:所有人可读
chmod 644 server.crt
chown root:root server.crt

# 3. 检查证书有效期
openssl x509 -in server.crt -noout -dates

# 4. 验证证书链完整性
openssl verify -CAfile ca-bundle.crt server.crt

# 5. 查看证书详细信息
openssl x509 -in server.crt -text -noout

5.2 常见问题解答

Q1: 通配符证书为什么必须 DNS 验证?

因为通配符证书覆盖所有子域名,CA 需要验证你对整个域名的控制权。HTTP 验证只能证明你控制某个特定主机,无法证明对整个域名的所有权。

Q2: CSR 可以重复使用吗?

不建议。每次申请新证书时应生成新的 CSR 和新的私钥,这样更安全,也能避免密钥泄露风险。

Q3: 证书链是什么?为什么重要?

根证书 Root CA 中间证书 Intermediate CA 服务器证书 Your Certificate

浏览器需要完整的信任链来验证证书。如果缺少中间证书,浏览器会报"证书不可信"错误。

Q4: JKS 和 PKCS#12 怎么互转?

# JKS → PKCS#12
keytool -importkeystore \
    -srckeystore server.jks -srcstoretype JKS \
    -destkeystore server.p12 -deststoretype PKCS12

# PKCS#12 → JKS
keytool -importkeystore \
    -srckeystore server.p12 -srcstoretype PKCS12 \
    -destkeystore server.jks -deststoretype JKS

Q5: 如何测试 HTTPS 配置?

# 测试 SSL 配置
openssl s_client -connect example.com:443 -servername example.com

# 在线测试工具
# https://www.ssllabs.com/ssltest/

六、总结

选择证书方案,就像选择出行方式:

  • 🚴 Let's Encrypt = 骑共享单车,免费、方便、适合短途(个人项目)
  • 🚗 OV 证书 = 开私家车,正式、体面、适合商务(企业官网)
  • 🚀 EV 证书 = 坐头等舱,顶级配置、严格审核(金融电商)

对于大多数个人开发者和小团队,Let's Encrypt 提供的免费自动化方案已经完全够用。企业场景则根据合规要求和信任级别选择合适的证书类型。

记住:私钥是核心机密,证书是公开身份,CSR 是申请书。搞懂这三者的关系,证书管理就不再神秘了。

✸ ✸ ✸

📜 版权声明

本文作者:王梓 | 原文链接:https://www.bthlt.com/note/369625131-Linux网站也要身份证:HTTPS 证书申请指南

出处:葫芦的运维日志 | 转载请注明出处并保留原文链接

📜 留言板

留言提交后需管理员审核通过才会显示